package com.llh.uua.conf

import com.llh.uua.filter.JwtFilter
import com.llh.uua.filter.RestAuthenticationFilter
import com.llh.uua.service.AccountService
import com.llh.uua.util.JsonUtil
import org.apache.logging.log4j.kotlin.Logging
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Bean
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.builders.WebSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
import org.springframework.security.core.Authentication
import org.springframework.security.core.AuthenticationException
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.security.web.authentication.AuthenticationFailureHandler
import org.springframework.security.web.authentication.AuthenticationSuccessHandler
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import kotlin.math.log

/**
 *
 *
 * Created At 2021/3/10 21:45
 * @author llh
 */
@EnableWebSecurity(debug = false)
class SecurityConfig : WebSecurityConfigurerAdapter(), Logging {

    @Autowired
    private lateinit var accountService: AccountService

    @Autowired
    private lateinit var jwtFilter: JwtFilter

    override fun configure(http: HttpSecurity) {

        http
            .formLogin { it.disable() }
            .csrf { it.disable() }
            .cors { it.disable() }
            .authorizeRequests {
                it.antMatchers("/authorize/**").permitAll()
                    .anyRequest().authenticated()
            }
            .addFilterAt(restAuthenticationFilter(), UsernamePasswordAuthenticationFilter::class.java)
            .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter::class.java)


    }

//    override fun configure(web: WebSecurity) {
//        web.ignoring().mvcMatchers(
//            "/public/**",
//            "/webjars/**",
//            "/authorize/**",
//            "demo/**")
//    }

    override fun configure(auth: AuthenticationManagerBuilder) {
        auth
            .userDetailsService(accountService)
            .passwordEncoder(passwordEncoder())
    }

    @Bean
    fun passwordEncoder(): PasswordEncoder {
        return BCryptPasswordEncoder()
    }

    fun restAuthenticationFilter(): RestAuthenticationFilter {
        val filter = RestAuthenticationFilter()
        filter.setAuthenticationFailureHandler(JsonLoginFailureHandler())
        filter.setAuthenticationSuccessHandler(JsonLoginSuccessHandler())
        filter.setAuthenticationManager(authenticationManager())
        filter.setFilterProcessesUrl("/authorize/login")
        return filter
    }


}

private class JsonLoginFailureHandler : AuthenticationFailureHandler {

    override fun onAuthenticationFailure(
        request: HttpServletRequest,
        response: HttpServletResponse,
        exception: AuthenticationException,
    ) {
        response.status = HttpStatus.UNAUTHORIZED.value()
        response.contentType = MediaType.APPLICATION_JSON_VALUE
        response.characterEncoding = "UTF-8"
        val errData = mapOf(
            "errMsg" to "认证失败",
            "data" to exception.message
        )
        response.writer.println(JsonUtil.mapper.writeValueAsString(errData))
    }


}

private class JsonLoginSuccessHandler : AuthenticationSuccessHandler, Logging {
    override fun onAuthenticationSuccess(
        request: HttpServletRequest,
        response: HttpServletResponse,
        authentication: Authentication,
    ) {
        response.status = HttpStatus.OK.value()
        response.contentType = MediaType.APPLICATION_JSON_VALUE
        response.characterEncoding = "UTF-8"
        val data = mapOf(
            "msg" to "认证成功",
        )
        response.writer.println(JsonUtil.mapper.writeValueAsString(data))
        logger.debug("认证成功")
    }
}